package com.hcc.gateway.netty.handler;

import cn.hutool.core.collection.CollectionUtil;
import com.hcc.gateway.netty.context.GatewayExchange;
import com.hcc.gateway.netty.filter.GatewayFilter;
import com.hcc.gateway.netty.filter.GatewayFilterChain;
import lombok.extern.slf4j.Slf4j;

import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * FilterContainer
 *
 * @author hushengjun
 * @date 2021/12/26
 */
@Slf4j
public class GatewayFilterHandler {

    private final List<GatewayFilter> filters;

    public GatewayFilterHandler(List<GatewayFilter> filters) {
        this.filters = filters.stream()
                .sorted((Comparator.comparingInt(GatewayFilter::getOrder)))
                .collect(Collectors.toList());
    }

    /**
     * 处理器
     * @param exchange
     * @return
     */
    public void handle(GatewayExchange exchange) {
        log.info(this.toString());

        new DefaultGatewayFilterChain(filters).filter(exchange);
    }

    @Override
    public String toString() {
        if (CollectionUtil.isEmpty(filters)) {
            return null;
        }

        StringBuilder str = new StringBuilder();
        for (GatewayFilter filter : filters) {
            str.append(String.format("[order=%s, filter=%s]", filter.getOrder(), filter.getClass().getSimpleName())).append("\n");
        }

        return str.toString();
    }

    /**
     * 默认实现的过滤链
     */
    private static class DefaultGatewayFilterChain implements GatewayFilterChain {

        private final int index;
        private final List<GatewayFilter> filters;

        DefaultGatewayFilterChain(List<GatewayFilter> filters) {
            this.filters = filters;
            this.index = 0;
        }

        private DefaultGatewayFilterChain(DefaultGatewayFilterChain parent, int index) {
            this.filters = parent.filters;
            this.index = index;
        }

        @Override
        public void filter(GatewayExchange exchange) {
            if (this.index >= filters.size()) {
                return;
            }

            GatewayFilter filter = filters.get(index);
            int nextIndex = this.index + 1;
            DefaultGatewayFilterChain filterChain = new DefaultGatewayFilterChain(this, nextIndex);

            filter.filter(exchange, filterChain);
        }

    }

}
